﻿using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System;
using System.Net;
using System.Diagnostics;
using ICSharpCode.SharpZipLib.Zip;
using IWshRuntimeLibrary;
using JetnettAutoUpdater.Properties;
using File = System.IO.File;

namespace JetnettAutoUpdater
{
    public partial class FormMain : Form
    {
        private readonly WebClient _downloadClient = new WebClient();
        private Stopwatch _downloadSpeedStopWatch = new Stopwatch();
        private NotifyIcon _icon = new NotifyIcon();
        private Timer _timer = new Timer();
        private ContextMenu _iconContextMenu = new ContextMenu();
        public FormMain()
        {
            InitializeComponent();
            this.Visible = false;
            this.FormClosing += AppClosing;
            _downloadClient.DownloadFileCompleted += DownloadFileComplete;
            _downloadClient.DownloadProgressChanged += DownloadProgressChanged;
           
            
            _icon.Icon = new Icon("jetnettNew.ico");
            _icon.Text = Resources.NotifyIcon_Text;
            _icon.Visible = true;
            _icon.Click += delegate(object sender, EventArgs args) { this.Show(); };

            _iconContextMenu.MenuItems.Add(0, new MenuItem("E&xit", (sender, args) => Application.Exit()));
            _iconContextMenu.MenuItems.Add(1,
                                           new MenuItem("&Check For Updates",
                                                        (sender, args) => CheckAndNotifyForUpdates()));

            _icon.ContextMenu = _iconContextMenu;
            //10 minutes
            _timer.Interval = (1000*60)*10;

            _timer.Tick += TimerTick;
            _timer.Start();

            CheckAndNotifyForUpdates();

        }

        void AppClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
                e.Cancel = true;
            this.Hide();
        }

        void TimerTick(object sender, EventArgs e)
        {
           CheckAndNotifyForUpdates();
        }
        void CheckAndNotifyForUpdates()
        {
            if (UpdatesAvailable())
            {
                _icon.BalloonTipTitle = Resources.BalloonTitle_UpdateAvailable;
                _icon.BalloonTipText = Resources.BalloonText_UpdatesAvailable;
                _icon.BalloonTipIcon = ToolTipIcon.Info;
                _icon.BalloonTipClicked += delegate
                                               { DoUpdates();
                                                                                       this.Show();
                };
                lblStatusMessage.Text = Resources.StatusMessage_UpdatesAvailable;
                _icon.ShowBalloonTip(5000);
            }
            else
            {

                lblStatusMessage.Text = Resources.StatusMessage_ApplicationsUpToDate;
            }
        }

        void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            var item = (KeyValuePair<string, List<KeyValuePair<string, string>>>) e.UserState;
            if (_downloadSpeedStopWatch != null)
                lblStatusMessage.Text = string.Format("Downloading {0}, {1:N2} mb/{2:N2} mb at {3:N2} kb/s", 
                                                        item.Key, 
                                                        (double)e.BytesReceived/1024/1024,
                                                        (double)e.TotalBytesToReceive/1024/1024, 
                                                        ((double)e.BytesReceived/1024) / (_downloadSpeedStopWatch.ElapsedMilliseconds/1000));
            progressBar1.Value = e.ProgressPercentage;

            if (e.BytesReceived == e.TotalBytesToReceive)
            {
       
                lblStatusMessage.Text = string.Format("{0} finished downloading", item.Key);
                if (_downloadSpeedStopWatch != null) _downloadSpeedStopWatch.Stop();
            }
        }

        void DownloadFileComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
        
            //stop the speed  watch
            _downloadSpeedStopWatch.Stop();
           
            var item = (KeyValuePair<string, List<KeyValuePair<string, string>>>) e.UserState;
            if (e.Error != null)
            {
                MessageBox.Show("Error! - " + item.Key + " - " + e.Error.Message);
                lblStatusMessage.Text = item.Key + " - " + e.Error.Message;
                return;
            }

            //extract 
            var fastZip = new FastZip();
            fastZip.ExtractZip(item.Key, Path.GetDirectoryName(item.Key), null);
            

            DownloadNextItem(item.Value);
        }

        private List<KeyValuePair<string, string>> downloadQueue = new List<KeyValuePair<string, string>>();
        private void DoUpdates()
        {
            this.Show();
            var files = Program.GetManifestFilesFromServer();

            foreach (string f in files)
            {
                var currentApp = Program.GetSettingsForApp(f);

                if (currentApp != null)
                {
                    //the execute file doesn't exist
                    if (!File.Exists(currentApp.ExecuteFile))
                    {
                        //download the whole thing
                        var remoteFile = new Uri(currentApp.RemoteURL.Replace("http://", "file://"));
                        if (remoteFile.IsFile)
                            downloadQueue.Add(new KeyValuePair<string, string>(currentApp.RemoteURL,currentApp.LocalDirectory + Path.GetFileName(remoteFile.LocalPath)));

                        //create the shortcuts
                        CreateDesktopShortcut(currentApp);
                        CreateStartMenuShortcut(currentApp);
                    }
                    else
                    {
                        //check local version
                        var info = FileVersionInfo.GetVersionInfo(currentApp.ExecuteFile);

                        var localVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart);
                        var remoteVersion = new Version();
                        if (currentApp.Version != null)
                            remoteVersion = new Version(currentApp.Version);

                        //we need to do update, just update the whole thing for now
                        if (remoteVersion > localVersion)
                        {

                            //Kill the current application if it's running
                            var procs = Process.GetProcessesByName(Path.GetFileName(currentApp.ExecuteFile));
                            foreach (var p in procs)
                                p.Kill();

                            //download the whole thing
                            var remoteFile = new Uri(currentApp.RemoteURL.Replace("http://", "file://"));
                            if (remoteFile.IsFile)
                                downloadQueue.Add(new KeyValuePair<string, string>(currentApp.RemoteURL, currentApp.LocalDirectory + Path.GetFileName(remoteFile.LocalPath)));
         
                        }
                    }

               
         

                }
            }
       
            //start downloading the items
            DownloadNextItem(downloadQueue);
        }
    
        private bool UpdatesAvailable()
        {
            var files = Program.GetManifestFilesFromServer();

            foreach (string f in files)
            {
                var currentApp = Program.GetSettingsForApp(f);

                if (currentApp != null)
                {
                    //the execute file doesn't exist
                    if (!File.Exists(currentApp.ExecuteFile))
                    {
                        return true;
                    }
                    else
                    {
                        //check local version
                        var info = FileVersionInfo.GetVersionInfo(currentApp.ExecuteFile);

                        var localVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart);
                        var remoteVersion = new Version();
                        if (currentApp.Version != null)
                           remoteVersion = new Version(currentApp.Version);

                        //we need to do update, just update the whole thing for now
                        if (remoteVersion > localVersion)
                        {

                            return true;
                        }
                    }

                }
            }
            return false;

        }
        private static void CreateStartMenuShortcut(AppConfigSettings appSettings)
        {
            //create shortcut
            var shell = new WshShellClass();

            var fullPathOfShortcut = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu) + "\\" + appSettings.StartMenuFolder + "\\" + appSettings.Name + ".lnk";
            var shortcut = (IWshShortcut)shell.CreateShortcut(fullPathOfShortcut);
            shortcut.TargetPath = appSettings.ExecuteFile;

            var directoryPath = Path.GetDirectoryName(fullPathOfShortcut);
            if (directoryPath != null && !Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            if (appSettings.IconPath != null)
                shortcut.IconLocation = appSettings.IconPath;
            shortcut.Description = "Start Menu Shortcut to " + appSettings.Name;
            shortcut.Save();
        }
        private static void CreateDesktopShortcut(AppConfigSettings appSettings)
        {
            //create shortcut
            var shell = new WshShellClass();

            var fullPathOfShortcut = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + appSettings.Name + ".lnk";
            var shortcut = (IWshShortcut)shell.CreateShortcut(fullPathOfShortcut);
            shortcut.TargetPath = appSettings.ExecuteFile;

            if (appSettings.IconPath != null)
                shortcut.IconLocation = appSettings.IconPath;
            shortcut.Description = "Desktop Shortcut to " + appSettings.Name;
            shortcut.Save();
        }

        private void DownloadNextItem(List<KeyValuePair<string,string>> downloadQueue )
        {
         
            //if we're empty, return
            if (downloadQueue.Count <= 0)
            {
                lblStatusMessage.Text = "Update Complete";
                return;
            }

            //get the current file we're going to download
            var fileToDownload = new KeyValuePair<string, string>(downloadQueue[0].Key, downloadQueue[0].Value);

            var directoryPath = Path.GetDirectoryName(fileToDownload.Value);
            if (directoryPath != null && !Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }
            //remove the file we're downloading from the queue
            downloadQueue.Remove(downloadQueue[0]);

            //start the download speed stopwatch
            _downloadSpeedStopWatch.Start();

            //store our pass along object in a keyValuePair <currently downloading file, our download queue>
            var passAlongObject = new KeyValuePair<string, List<KeyValuePair<string, string>>>(fileToDownload.Value,downloadQueue);

            //start downloading
            _downloadClient.DownloadFileAsync(new Uri(fileToDownload.Key), fileToDownload.Value, passAlongObject );
        }
        private static List<KeyValuePair<string, string>> CreateDownloadFileListForApplication(AppConfigSettings currentApplication)
        {
            var kvp = new List<KeyValuePair<string, string>>();
            var downloadQueue = new List<string>(Program.GetFilesFromServerDirectory(currentApplication.RemoteURL));

            for (int i = 0; i < downloadQueue.Count; i++)
            {
                kvp.Add(new KeyValuePair<string, string>(currentApplication.RemoteURL + downloadQueue[i], currentApplication.LocalDirectory + downloadQueue[i].Replace("[config]", "config")));
            }
            return kvp;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CheckAndNotifyForUpdates();

        }

        private void button2_Click(object sender, EventArgs e)
        {
            DoUpdates();
        }

     

   

        
    }
}
